#include "ui_dragwidget.h"
#include "ui_manager.h"

#include "console/console.h"

#include "input/mouse.h"
#include "script/scripthelper.h"
#include "script/write_lua.h"

#include "util/timer.h"		    // Needs to come in early
#include "util/mmgr.h"		    // Needs to come in early
#include "util/common_macros.h"		// macros
#include "util/log.h"		    // logging
#ifdef _ENABLE_LUABIND
#include <luabind/luabind.hpp>
#include <luabind/copy_policy.hpp>
#endif // _ENABLE_LUABIND

#include <cassert>

using namespace ui;


UIWidget*	UIDragWidget::s_pDragTarget = NULL;
math::Vec2	UIDragWidget::s_DragOffset;

UIDragWidget::UIDragWidget(UIWidget* pParent, const std::string& Name) :
	UIWidget(pParent, Name),
	m_pParentPanel(NULL),
	m_pDragParent(NULL),
	m_StartDragScript(""),
	m_EndDragScript(""),
	m_DoNotPushToFront(false),
	m_InitDragData(true),
	m_StartY(0),
	m_IsAlreadySetStartY(false)
{
	m_Type = WT_DRAG;
}

UIDragWidget::~UIDragWidget()
{
	if (this == s_pDragTarget)
		s_pDragTarget = NULL;
}

bool UIDragWidget::Load(LuaPlus::LuaObject& _LObj)
{
	using namespace script;

	UIWidget::Load(_LObj);

	m_StartDragScript	= ScriptHelper::GetTableString(_LObj, "StartDragScript", "");
	m_EndDragScript		= ScriptHelper::GetTableString(_LObj, "EndDragScript", "");
	m_DoNotPushToFront	= ScriptHelper::GetTableBool(_LObj, "DoNotPushToFront", false);

	// disable drag flag -- UIDragWidget uses different method of dragging
	SetCanDrag(false);

	return true;
}

bool UIDragWidget::Tick(float dt)
{
	if (m_InitDragData) // first time init
	{
		// get main panel
		m_pParentPanel = this;
		while (m_pParentPanel->GetParent())
			m_pParentPanel = m_pParentPanel->GetParent();

		// get drag parent -- must not be main panel
		m_pDragParent = GetParent();
		if (!m_pDragParent || (m_pDragParent == m_pParentPanel))
			m_pDragParent = this;

		m_InitDragData = false;

		
			
	}

	if (UIWidget::Tick(dt))
	{
		math::Vec2 Pos = GET_MOUSE().GetPos();
		bool LButtonDown = GET_MOUSE().GetButtonState(input::Mouse::BUTTON_LEFT)->ButtonDown;

		if (s_pDragTarget && (m_pDragParent == s_pDragTarget))
		{
			if (LButtonDown)
			{
				math::Vec2 UIPos = s_pDragTarget->GetPosition();
				math::Vec2 Offset = Pos - UIPos;

				// chit: we don't need X to move around
				UIPos.y += (Offset.y - s_DragOffset.y);
				//UTIL_CLAMP(UIPos.x, 0.0f, 1.0f - s_pDragTarget->GetSize().x);
				UTIL_CLAMP(UIPos.y, 0 
									, m_StartY);

				s_pDragTarget->SetPositionRelativeToParent(UIPos);
			}
			else
			{
				s_pDragTarget = NULL;
				if (!m_EndDragScript.empty())
					console::Console::Instance().Do(m_EndDragScript);
			}
		}
		else if (LButtonDown)
		{
			// now handled in mousepress event
			/*
			if (!s_pDragTarget && IsInside(Pos))
			{
				if (s_pDragTarget = m_pDragParent)
				{
					s_DragOffset = Pos - s_pDragTarget->GetPosition();
					if (!m_DoNotPushToFront)
						ui::UIManager::Instance().PushPanelToFront(m_pParentPanel);
					if (!m_StartDragScript.empty())
						console::Console::Instance().Do(m_StartDragScript);
				}
			}
			*/
		}
		else if (s_pDragTarget)
		{
			// this condition should only ever occur if the previous drag target was prematurely interrupted,
			// e.g. --
			// destroyed,
			// set hidden,
			// set not active,
			// etc.
			// -- which usually shouldn't occur DURING a drag operation;
			// the only consequence in such cases would be the end drag script failing to activate,
			// so we can just safely ignore that
			s_pDragTarget = NULL;
		}

		
		return true;
	}
	return false;
}

bool UIDragWidget::Render(bool Force)
{
	return UIWidget::Render(Force);
}

bool UIDragWidget::OnMousePress(const math::Vec2& Pos, unsigned int Button)
{
	bool bRet = UIWidget::OnMouseDown(Pos, Button);

	if (!m_InitDragData && !s_pDragTarget && (input::Mouse::BUTTON_LEFT == Button) && IsInside(Pos))
	{
		if (s_pDragTarget = m_pDragParent)
		{
			if(!m_IsAlreadySetStartY)
			{
				m_StartY = s_pDragTarget->GetPosition().y;
				m_IsAlreadySetStartY = true;
			}
			s_DragOffset = Pos - s_pDragTarget->GetPosition();
			if (!m_DoNotPushToFront)
				ui::UIManager::Instance().PushPanelToFront(m_pParentPanel);
			if (!m_StartDragScript.empty())
				console::Console::Instance().Do(m_StartDragScript);
		}
	}

	return bRet;
}

UIWidget* UIDragWidget::GetClone()
{
	UIDragWidget* pWidget = new UIDragWidget(m_pParent, GetCloneName(m_Name));
	FillCloneInfo( (UIWidget*)pWidget );

	pWidget->m_StartDragScript	= m_StartDragScript;
	pWidget->m_EndDragScript	= m_EndDragScript;
	pWidget->m_DoNotPushToFront	= m_DoNotPushToFront;

	return pWidget;
}

bool UIDragWidget::ExportSpecificsToFile(script::WriteLua* pWL)
{
	if (!m_StartDragScript.empty())
		pWL->WritePair("StartDragScript", m_StartDragScript);

	if (!m_EndDragScript.empty())
		pWL->WritePair("EndDragScript", m_EndDragScript);

	if (m_DoNotPushToFront)
		pWL->WritePair("DoNotPushToFront", (int)1);

	return true;
}

void UIDragWidget::Register(LuaPlus::LuaState* _pScript)
{
#ifdef _ENABLE_LUABIND
	// TODO: register script functions
	
	using namespace luabind;
	
	lua_State * L = _pScript->GetCState ( );

	luabind::module(L)
    [
		luabind::class_<UIDragWidget, UIWidget >( "DragWidget" )
	    .def( "GetStartDragScript",		&UIDragWidget::GetStartDragScript)
		.def( "SetStartDragScript",		&UIDragWidget::SetStartDragScript)
		.def( "GetEndDragScript",		&UIDragWidget::GetEndDragScript)
		.def( "SetEndDragScript",		&UIDragWidget::SetEndDragScript)
		.def( "DoNotPushToFront",		&UIDragWidget::DoNotPushToFront)
		.def( "SetPushToFront",			&UIDragWidget::SetPushToFront)
	];
#endif // _ENABLE_LUABIND    
	
}
